package com.xyl.audio.utils;

import android.util.Log;

import com.lansosdk.videoeditor.LanSongFileUtil;
import com.lansosdk.videoeditor.VideoEditor;
import com.lansosdk.videoeditor.onVideoEditorProgressListener;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import static com.lansosdk.videoeditor.LanSongFileUtil.fileExist;

/**
 * @author xyl on 2019/7/16.
 */
public class AudioUtils {
    public final static String TAG = "AudioUtils";
    private VideoEditor editor;

    public AudioUtils() {
        editor = new VideoEditor();
        editor.setOnProgessListener(new onVideoEditorProgressListener() {
            @Override
            public void onProgress(VideoEditor v, int percent) {
                if (monAudioEditorProgressListener != null) {
                    monAudioEditorProgressListener.onProgress(AudioUtils.this, percent);
                }
            }
        });
    }

    private onAudioEditorProgressListener monAudioEditorProgressListener = null;

    public void setOnAudioEditorProgressListener(onAudioEditorProgressListener listener) {
        monAudioEditorProgressListener = listener;
    }

    /**
     * 进度监听
     */
    public interface onAudioEditorProgressListener {
        void onProgress(AudioUtils v, int percent);
    }

    /**
     * 1、音频解码成pcm
     * 把输入的音频(或含有音频视频)转为单声道,并可以设置采样率
     *
     * @param inputAudio 输入原文件的完整路径
     * @param dstSample  要设置的采样率, 如果不变,则设置为-1;
     * @return
     */
    public String executeConvertToPCM(String inputAudio, int dstSample) {
        if (LanSongFileUtil.fileExist(inputAudio)) {
            String dstPath = LanSongFileUtil.createPCMFileInBox();
            List<String> cmdList = new ArrayList<String>();
            cmdList.add("-i");
            cmdList.add(inputAudio);
            cmdList.add("-vn");
            cmdList.add("-f");
            cmdList.add("s16le");
            cmdList.add("-ac");
            cmdList.add("1");
            cmdList.add("-acodec");
            cmdList.add("pcm_s16le");
            if (dstSample > 0) {
                cmdList.add("-ar");
                cmdList.add(String.valueOf(dstSample));
            }
            cmdList.add("-y");
            cmdList.add(dstPath);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = cmdList.get(i);
            }
            int ret = editor.executeVideoEditor(command);
            if (ret == 0) {
                Log.e(TAG, "executeConvertToWav path=" + dstPath);
                return dstPath;
            } else {
                Log.e(TAG, "executeConvertToWav 失败, 请查看打印信息");
                return null;
            }
        } else {
            Log.e(TAG, "executeConvertToWav 执行失败, 文件不存在");
            return null;
        }
    }

    /**
     * 2、两个pcm混合.
     *
     * @param srcPach1    pcm格式的主音频
     * @param samplerate  主音频采样率
     * @param channel     主音频通道数
     * @param srcPach2    pcm格式的次音频
     * @param samplerate2 次音频采样率
     * @param channel2    次音频通道数
     * @param value1      主音频的音量
     * @param value2      次音频的音量
     * @return 输出文件.输出也是pcm格式的音频文件.
     */
    public String executePcmMix(String srcPach1, int samplerate, int channel, String srcPach2, int samplerate2, int
            channel2, float value1, float value2) {
        List<String> cmdList = new ArrayList<String>();

        String filter = String.format(Locale.getDefault(), "[0:a]volume=volume=%f[a1]; [1:a]volume=volume=%f[a2]; " +
                "[a1][a2]amix=inputs=2:duration=first:dropout_transition=2", value1, value2);

        String dstPath = LanSongFileUtil.createFileInBox("pcm");

        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach1);

        cmdList.add("-f");

        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate2));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel2));
        cmdList.add("-i");
        cmdList.add(srcPach2);

        cmdList.add("-y");
        cmdList.add("-filter_complex");
        cmdList.add(filter);
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-acodec");
        cmdList.add("pcm_s16le");
        cmdList.add(dstPath);


        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = cmdList.get(i);
        }
        int ret = editor.executeVideoEditor(command);
        if (ret == 0) {
            return dstPath;
        } else {
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 3、把pcm格式的音频文件编码成AAC
     *
     * @param srcPach    源pcm文件
     * @param samplerate pcm的采样率
     * @param channel    pcm的通道数
     * @return 输出的aac合成后的文件
     */
    public String executePcmEncodeAac(String srcPach, int samplerate, int channel) {
        List<String> cmdList = new ArrayList<String>();

        String dstPath = LanSongFileUtil.createAACFileInBox();
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach);


        cmdList.add("-acodec");
        cmdList.add("libfaac");
        cmdList.add("-b:a");
        cmdList.add("64000");
        cmdList.add("-y");

        cmdList.add(dstPath);

        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = cmdList.get(i);
        }
        int ret = editor.executeVideoEditor(command);
        if (ret == 0) {
            return dstPath;
        } else {
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 4、把pcm格式的音频文件编码成m4a
     *
     * @param srcPach    源pcm文件
     * @param samplerate pcm的采样率
     * @param channel    pcm的通道数
     * @param dstSample  在转换为mp3的时候, 调整mp3的采样率;如不变,设置为0
     * @return 输出的m4a合成后的文件
     */
    public String executePcmEncodeM4a(String srcPach, int samplerate, int channel, int dstSample) {
        List<String> cmdList = new ArrayList<String>();

        String dstPath = LanSongFileUtil.createM4AFileInBox();
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach);


        cmdList.add("-acodec");
        cmdList.add("libfaac");
        cmdList.add("-b:a");
        cmdList.add("128000");

        cmdList.add("-ac");
        cmdList.add("2");

        if (dstSample > 0) {
            cmdList.add("-ar");
            cmdList.add(String.valueOf(dstSample));
        }
        cmdList.add("-y");
        cmdList.add(dstPath);

        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = cmdList.get(i);
        }
        int ret = editor.executeVideoEditor(command);
        if (ret == 0) {
            return dstPath;
        } else {
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 6、把pcm格式的音频文件编码成mp3
     *
     * @param srcPach    源pcm文件
     * @param samplerate pcm的采样率
     * @param channel    pcm的通道数
     * @param dstSample  在转换为mp3的时候, 调整mp3的采样率;如不变,设置为0
     * @return 输出的m4a合成后的文件
     * <p>
     * //pcm转成mp3命令用到了libmp3lame
     * //-y覆盖已有文件
     * //-ac设置声道数，1就是单声道，2就是立体声
     * //-ar设置音频采样率 (单位：Hz)
     * //-f指定格式(音频或视频格式) s16le16 位有符号数
     * //-i输入文件pcm
     * //-c:a
     * //-q:a
     */
    public String executePcmEncodeMp3(String srcPach, int samplerate, int channel, int dstSample) {
        List<String> cmdList = new ArrayList<String>();

        String dstPath = LanSongFileUtil.createMP3FileInBox();
        cmdList.add("-f");
        cmdList.add("s16le");
        cmdList.add("-ar");
        cmdList.add(String.valueOf(samplerate));
        cmdList.add("-ac");
        cmdList.add(String.valueOf(channel));
        cmdList.add("-i");
        cmdList.add(srcPach);

        cmdList.add("-acodec");
        cmdList.add("libmp3lame");
        cmdList.add("-b:a");
        cmdList.add("128000");

        cmdList.add("-ac");
        cmdList.add("1");//声道数

        if (dstSample > 0) {
            cmdList.add("-ar");
            cmdList.add(String.valueOf(dstSample));
        }
        cmdList.add("-y");
        cmdList.add(dstPath);

        String[] command = new String[cmdList.size()];
        for (int i = 0; i < cmdList.size(); i++) {
            command[i] = cmdList.get(i);
        }
        int ret = editor.executeVideoEditor(command);
        if (ret == 0) {
            return dstPath;
        } else {
            LanSongFileUtil.deleteFile(dstPath);
            return null;
        }
    }

    /**
     * 7、音频拼接
     *
     * @param tsArray 音频文件数组
     * @param dstFile 生成的目标文件
     * @return
     */
    public int concatAudio(String[] tsArray, String dstFile) {
        // ffmpeg -i "concat:a.mp3|a1.mp3" -acodec copy a2.mp3
        if (LanSongFileUtil.filesExist(tsArray)) {
            String concat = "concat:";
            for (int i = 0; i < tsArray.length - 1; i++) {
                concat += tsArray[i];
                concat += "|";
            }
            concat += tsArray[tsArray.length - 1];

            List<String> cmdList = new ArrayList<String>();

            cmdList.add("-i");
            cmdList.add(concat);

            cmdList.add("-c");
            cmdList.add("copy");

            cmdList.add("-y");

            cmdList.add(dstFile);
            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = cmdList.get(i);
            }
            return editor.executeVideoEditor(command);
        } else {
            return -1;
        }
    }

    /**
     * 8、音频裁剪,截取音频文件中的一段.
     *
     * @param srcFile   源音频
     * @param startS    开始时间,单位是秒. 可以有小数
     * @param durationS 裁剪的时长.
     * @return
     */
    public String executeCutAudio(String srcFile, float startS, float durationS) {
        if (fileExist(srcFile)) {

            List<String> cmdList = new ArrayList<String>();

            String dstFile = LanSongFileUtil.createM4AFileInBox();

            cmdList.add("-i");
            cmdList.add(srcFile);

            cmdList.add("-ss");
            cmdList.add(String.valueOf(startS));

            cmdList.add("-t");
            cmdList.add(String.valueOf(durationS));

            cmdList.add("-vn");
//            cmdList.add("-acodec");
//            cmdList.add("copy");

            //2019-04-26 09:32:40 强制为faac编码;
            cmdList.add("-acodec");
            cmdList.add("libfaac");

            cmdList.add("-ac");
            cmdList.add("2");

            cmdList.add("-ar");
            cmdList.add("44100");

            cmdList.add("-b:a");
            cmdList.add("128000");


            cmdList.add("-y");
            cmdList.add(dstFile);

            String[] command = new String[cmdList.size()];
            for (int i = 0; i < cmdList.size(); i++) {
                command[i] = cmdList.get(i);
            }
            int ret = editor.executeVideoEditor(command);
            if (ret == 0) {
                return dstFile;
            } else {
                LanSongFileUtil.deleteFile(dstFile);
                return null;
            }
        } else {
            return null;
        }
    }

}
